#include "PageCache.h"
#include "Common.h"
PageCache PageCache::_sInt;

span* PageCache::newspan(size_t k)
{
	assert(k > 0 );
	if (k > NPAGES-1)
	{

		void* ptr = SystemAlloc(k);
		span* nspan;
		nspan->_pageid = (PAGE_ID)ptr >> PAGE_SHIFT;
		nspan->_pagenum = k;

		_isSpanmap[nspan->_pageid] = nspan;
		return nspan;
	}
	if (!_spanlist[k].empty())
	{
		span* need =  _spanlist[k].popfront();
		return need;
	}
	else
	{
		for (size_t i = k; k < NPAGES; i++)
		{
			if (!_spanlist[i].empty())
			{
				span* nspan = _spanlist[i].popfront();
				//span* kspan = new span;
				span* kspan = _spanPool.New();    //使用tcmalloc更具优势

				kspan->_pageid = nspan->_pageid;
				kspan->_pagenum = k;



				nspan->_pageid += k;
				nspan->_pagenum -= k;

				_spanlist[nspan->_pagenum].pushfront(nspan);

				return kspan;
			}
		}
	}

	//span* bigspan = new span;
	span* bigspan = _spanPool.New();
	void* ptr = SystemAlloc(NPAGES - 1);
	bigspan->_pageid = (PAGE_ID)ptr >> PAGE_SHIFT;
	bigspan->_pagenum = NPAGES - 1;
	_spanlist[bigspan->_pagenum].pushfront(bigspan);
	return newspan(k);

}

span* PageCache::mapobjecttospan(void* obj)
{
	PAGE_ID id = (PAGE_ID)obj >> PAGE_SHIFT;
	auto it = _isSpanmap.find(id);
	if (it != _isSpanmap.end())
	{
		return it->second;
	}
	else
	{
		return nullptr;
	}

	
}

void PageCache::RealsespantoPage(span* span)
{
    //span过大直接还给堆
	if (span->_pagenum > NPAGES - 1)
	{
		void* ptr = (void*)(span->_pageid << PAGE_SHIFT);
		SystemFree(ptr);
		_spanPool.Delete(span);
		return;
	}
	//对span前面的页进行内存合并，以缓解内存碎片问题
	while (1)
	{
		PAGE_ID prevID = span->_pageid - 1;
		auto ret = _isSpanmap.find(prevID);
		span*prev = ret->second;
		if (ret == _isSpanmap.end()) //确保是否存在
		{
			break;
		}
		if (prev._isUse == true)   //确保span没有被使用
		{
			break;
		}
		if (span->_pagenum + prev->_pagenum > NPAGES - 1)   //确保合并后的页大小不会超过最大页的大小
		{
			break;
		}
		span->_pageid = prev = prev->_pageid;
		span->_pagenum += prev->_pagenum;

		_spanlist[prev->_pagenum].erase(prev);
		_spanPool.Delete(prev);
	}
	//对span后面的页进行内存合并，以缓解内存碎片问题
	while (1)
	{
		PAGE_ID nextID = span->_pageid + span->_pagenum;
		auto ret = _isSpanmap.find(nextID);
		span* nextspan = ret->second;
		if (ret == _isSpanmap.end())
		{
			break;
		}
		if (nextspan._isUse == true)
		{
			break;
		}
		if (nextspan->_pagenum + span->_pagenum > NPAGES)
		{
			break;
		}
		span->_pagenum += nextspan->_pagenum;
		_spanlist[nextspan->_pagenum].erase(nextspan);
		//delete nextspan;
		_spanPool.Delete(nextspan);
	}
	_spanlist[span->_pagenum].pushfront(span);
	span->_isUse = false;
	//完成span的首尾映射
	_isSpanmap[span->_pageid] = span;
	_isSpanmap[span->_pageid + span->_pagenum - 1] = span;
}
